package com.tiantian.web.controller.topic;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.tiantian.common.annotation.Log;
import com.tiantian.common.constant.JudgeConstants;
import com.tiantian.common.constant.TopicConstants;
import com.tiantian.common.core.controller.BaseController;
import com.tiantian.common.core.domain.ResponseResult;
import com.tiantian.common.core.domain.entity.SysJudger;
import com.tiantian.common.core.domain.entity.SysUser;
import com.tiantian.common.core.domain.vo.SysJudgerVO;
import com.tiantian.common.core.page.TableDataInfo;
import com.tiantian.common.validator.group.AddGroup;
import com.tiantian.common.enums.BusinessType;
import com.tiantian.common.enums.OperatorType;
import com.tiantian.common.exception.BusinessException;
import com.tiantian.common.utils.DateUtils;
import com.tiantian.common.utils.StringUtils;
import com.tiantian.system.service.ISysUserService;
import com.tiantian.topic.domain.dto.QueryReplySubDTO;
import com.tiantian.topic.domain.entity.SysReplay;
import com.tiantian.topic.domain.sdo.SysJudgeScoreSDO;
import com.tiantian.topic.domain.vo.CandidateVO;
import com.tiantian.topic.domain.vo.SubInfoVO;
import com.tiantian.topic.domain.vo.SysJudgeDetailVO;
import com.tiantian.topic.domain.vo.SysJudgeVO;
import com.tiantian.topic.mapper.SysJudgeMapper;
import com.tiantian.topic.mapper.SysJudgerMapper;
import com.tiantian.topic.service.SysJudgeService;
import com.tiantian.topic.service.SysReplyService;
import com.tiantian.topic.service.SysTopicService;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 判题 判题人
 *
 * @author TianTian
 */
@RequiredArgsConstructor
@RestController
@RequestMapping("/judge")
public class SysJudgeController extends BaseController {


    private final SysJudgeService sysJudgeService;
    private final ISysUserService sysUserService;
    private final SysTopicService sysTopicService;
    private final SysReplyService sysReplyService;
    private final SysJudgeMapper sysJudgeMapper;

    /**
     * 分页查询判题列表
     *
     * @param sysJudgeVO 查询参数
     * @return 分页数据
     */
    @GetMapping("/list")
    @SaCheckPermission("judge")
    public TableDataInfo getJudgeList(SysJudgeVO sysJudgeVO) {
        startPage();
        // 判查询选参数是否为[我需要判的题]
        if (sysJudgeVO.getNeedMe() != null && sysJudgeVO.getNeedMe()) {
            sysJudgeVO.setJudger(getNickName());
        }
        List<SysJudgeVO> sysJudgeVOList = sysJudgeService.selectJudgeList(sysJudgeVO);
        // 设置题人
        for (SysJudgeVO judgeVO : sysJudgeVOList) {
            judgeVO.setJudger(sysJudgeMapper.selectJudgerByUserId(judgeVO.getUserId()));
        }
        return getDataTable(sysJudgeVOList);
    }

    /**
     * 根据用户ID查询判题信息
     *
     * @param userId 用户ID
     * @return SysJudgeVO
     */
    @GetMapping("/info/{userId}")
    @SaCheckPermission("judge")
    public ResponseResult<SysJudgeVO> getJudgeInfo(@PathVariable Long userId) {
        SysJudgeVO sysJudgeVO = sysJudgeService.selectJudgeInfoByUserId(userId);
        SysUser sysUser = sysUserService.selectUserById(userId);
        sysJudgeVO.setTotalScore(sysUser.getTotalScore());
        return ResponseResult.ok(sysJudgeVO);
    }

    /**
     * 根据用户ID查询判断详细信息列表
     *
     * @param userId 用户ID
     * @return 答题信息列表
     */
    @GetMapping("/detailList/{userId}")
    @SaCheckPermission("judge")
    public ResponseResult<List<SysJudgeDetailVO>> getJudgeDetailList(@PathVariable String userId) {
        List<SysJudgeDetailVO> sysJudgeDetailVOS = sysJudgeService.selectJudgeDetailListByUserId(userId);
        return ResponseResult.ok(sysJudgeDetailVOS);
    }

    /**
     * 获取提交信息
     *
     * @param queryReplySubDTO 查询参数
     */
    @GetMapping("/subInfo")
    @SaCheckPermission("judge")
    public TableDataInfo getSubInfo(QueryReplySubDTO queryReplySubDTO) {
        startPage();
        List<SubInfoVO> subInfoVOList = sysJudgeService.selectSubInfo(queryReplySubDTO);
        for (SubInfoVO subInfoVO : subInfoVOList) {
            int subCount = subInfoVO.getSubCount();
            // 设置提交状态
            String subStatus;
            if (subCount == 0) {
                subStatus = JudgeConstants.NOT_SUBMITTED;
                // 小于题目总数
            } else if (subCount < sysTopicService.getTopicTotal()) {
                subStatus = JudgeConstants.PARTIAL_SUBMISSION;
            } else {
                subStatus = JudgeConstants.FULL_SUBMISSION;
            }
            subInfoVO.setSubStatus(subStatus);
        }
        return getDataTable(subInfoVOList);
    }

    /**
     * 获取提交的总信息
     */
    @GetMapping("/subTotal")
    @SaCheckPermission("judge")
    public ResponseResult<Map<String, Object>> getSubTotal() {
        Map<String, Object> ajax = new HashMap<>();
        ajax.put("registerTotal", sysUserService.countNewcomer());
        ajax.put("subTotal", sysJudgeService.selectSubTotal());
        ajax.put("notSubTotal", sysJudgeService.selectNotSubTotal());
        return ResponseResult.ok(ajax);
    }

    /**
     * 批量修改分数
     *
     * @param sysJudgeScoreList 评分集合
     * @return 评分信息
     */
    @PostMapping("/setScore")
    @SaCheckPermission("judge")
    @Log(title = "判题评分", businessType = BusinessType.JUDGE_TOPIC, operatorType = OperatorType.ADMIN)
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Map<String, Object>> setJudgeScoreBatch(@RequestBody List<SysJudgeScoreSDO> sysJudgeScoreList) {
        // 校验参数
        checkParameter(sysJudgeScoreList);

        Long userId = getUserId();
        // 判断当前用户是否为判题人
        SysJudger sysJudger = sysJudgeService.selectJudgerByUserId(userId);
        if (ObjectUtil.isNull(sysJudger)) {
            throw new BusinessException("无权限判题");
        }

        // 判断该判题人是否有权限进行评分
        Long replyUserId = null;
        for (SysJudgeScoreSDO sysJudgeScoreSDO : sysJudgeScoreList) {
            SysReplay sysReplay = sysReplyService.selectById(sysJudgeScoreSDO.getReplyId());
            String replyId = sysReplay.getReplyId();
            // 答题用户Id
            replyUserId = sysReplay.getUserId();
            // 当判题人不是当前用户时
            if (!Objects.equals(userId, sysReplay.getJudgerId())) {
                throw new BusinessException(StringUtils.format("无权判题: {}, 未被分配该题目", replyId));
            }
        }

        String nickName = getNickName();
        // 判断是否有某一个题目已经完成评分
        Map<String, Object> ajax = new HashMap<>();
        int totalScore = 0;
        for (SysJudgeScoreSDO sysJudgeScoreSDO : sysJudgeScoreList) {
            // 设置判题人姓名
            sysJudgeScoreSDO.setJudger(nickName);
            // 设置判状态
            sysJudgeScoreSDO.setStatus(TopicConstants.JUDGE_FINISHED);
            // 累加单题分数
            totalScore += sysJudgeScoreSDO.getScore();
        }

        // 批量更新单题分数
        int update1 = sysJudgeService.updateScoreByReplyId(sysJudgeScoreList);
        // 设置该答题用户的总分
        int update2 = sysUserService.setNewcomerTotalScore(replyUserId, totalScore);
        if (update1 * update2 > 0) {
            // 构造判题信息
            ajax.put("sysJudgeScoreList", sysJudgeScoreList);
            ajax.put("subTime", DateUtils.getTime());
            ajax.put("judger", getNickName());
            ajax.put("totalScore", totalScore);
            // 返回评分信息
            return ResponseResult.ok("评分成功", ajax);
        }
        return ResponseResult.fail("判题失败, 请联系管理员");
    }

    /**
     * 获取判题人列表
     *
     * @param sysJudger 查询参数
     */
    @GetMapping("/judgerList")
    @SaCheckPermission("setting")
    public TableDataInfo getJudgerList(SysJudger sysJudger) {

        List<SysJudger> sysJudgerList = sysJudgeService.selectJudgerList(sysJudger);
        if (CollUtil.isEmpty(sysJudgerList)) {
            return getDataTable(new ArrayList<>());
        }
        // 属性拷贝
        List<SysJudgerVO> sysJudgerVOList = BeanUtil.copyToList(sysJudgerList, SysJudgerVO.class);

        for (SysJudgerVO judgerVO : sysJudgerVOList) {
            // 设置用户和判题数目
            List<String> nickNames = new ArrayList<>();
            if (CollUtil.isNotEmpty(judgerVO.getReplyUsers())) {
                for (Long replyUserId : judgerVO.getReplyUsers()) {
                    SysUser sysUser = sysUserService.selectUserById(replyUserId);
                    if (ObjectUtil.isNotNull(sysUser)) {
                        nickNames.add(sysUser.getNickName());
                    }
                }
            }
            Set<String> statusSet = new HashSet<>();
            // 设置判题状态
            if (CollUtil.isNotEmpty(judgerVO.getReplyIds())) {
                for (String replyId : judgerVO.getReplyIds()) {
                    // 判断各个题目是否已经判题完毕
                    SysReplay sysReplay = sysReplyService.selectById(replyId);
                    if (ObjectUtil.isNotNull(sysReplay)) {
                        statusSet.add(sysReplay.getStatus());
                    }
                }
            }
            String status = statusSet.size() == 1 && statusSet.contains("1") ? "1" : "0";
            judgerVO.setStatus(status);
            judgerVO.setNickNames(nickNames);
            judgerVO.setCount(judgerVO.getReplyIds().size());
        }

        return getDataTable(sysJudgerVOList);
    }

    /**
     * 获取候选人列表
     */
    @GetMapping("/candidate")
    @SaCheckPermission("setting")
    public ResponseResult<List<CandidateVO>> getCandidate() {
        List<SysUser> sysUsers = sysUserService.selectCandidate();
        List<CandidateVO> candidateVOList = BeanUtil.copyToList(sysUsers, CandidateVO.class);
        return ResponseResult.ok(candidateVOList);
    }

    /**
     * 添加判题人
     */
    @PostMapping("/judger")
    @SaCheckPermission("setting")
    @Log(title = "判题人设置", businessType = BusinessType.JUDGE_SETTING, operatorType = OperatorType.ADMIN, isSaveResponseData = false)
    public ResponseResult<Void> addJudger(@RequestBody @Validated(AddGroup.class) SysJudger sysJudger) {
        // 判断是否已经是判题人
        Long userId = sysJudger.getUserId();
        SysJudger o = sysJudgeService.selectJudgerByUserId(userId);
        if (ObjectUtil.isNotNull(o)) {
            throw new BusinessException("该用户已经为判题人, 请勿多次设置");
        }
        SysUser sysUser = sysUserService.selectUserById(userId);
        if (ObjectUtil.isNull(sysUser)) {
            throw new BusinessException("用户不存在, 注册判题人失败");
        }
        // 参数设置
        sysJudger.setJudgerId(IdUtil.getSnowflakeNextIdStr());
        sysJudger.setJudgerName(sysUser.getNickName());
        setCommonFieldInsert(sysJudger);
        int rows = sysJudgeService.insertJudger(sysJudger);
        return toAjax(rows);
    }

    /**
     * 删除判题人(物理删除)
     *
     * @param judgerId 判题人ID
     */
    @DeleteMapping("/delJudger/{judgerId}")
    @SaCheckPermission("setting")
    @Log(title = "删除判题人", businessType = BusinessType.JUDGER_DELETE, operatorType = OperatorType.ADMIN, isSaveResponseData = false)
    public ResponseResult<Void> delJudger(@PathVariable String judgerId) {
        int row = sysJudgeService.deleteJudgerById(judgerId);
        return toAjax(row);
    }

    /**
     * 参数校验
     */
    private void checkParameter(List<SysJudgeScoreSDO> sysJudgeScoreList) {
        if (CollUtil.isEmpty(sysJudgeScoreList)) {
            throw new BusinessException("参数不能为空");
        }
        for (SysJudgeScoreSDO sysJudgeScoreSDO : sysJudgeScoreList) {
            // 如果两个参数中有一个为空
            if (!StrUtil.isAllNotEmpty(sysJudgeScoreSDO.getReplyId(), sysJudgeScoreSDO.getScore().toString())) {
                throw new BusinessException("参数不能为空");
            }
        }
    }
}
